package com.xmh.util;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

import com.obs.services.ObsClient;
import com.obs.services.ObsConfiguration;
import com.obs.services.exception.ObsException;
import com.obs.services.model.CompleteMultipartUploadRequest;
import com.obs.services.model.InitiateMultipartUploadRequest;
import com.obs.services.model.InitiateMultipartUploadResult;
import com.obs.services.model.ObsObject;
import com.obs.services.model.PartEtag;
import com.obs.services.model.UploadPartResult;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
@PropertySource(value = "classpath:HuaWeiCloudFile.properties")
public class HuaWeiCloudFileUtil {

	private static String ak;

	private static String sk;

	private static String hotBucketName;

	private static String lowBucketName;

	private static String bakBucketName;

	private static String endPoint;

	private static String dowloadFilePath;

	private static ObsClient obsClient;

	private static Boolean isInit = true;

	/**
	 * 打开链接捅
	 */
	private static ObsClient openConnection() {
		ObsConfiguration config = new ObsConfiguration();
		config.setSocketTimeout(30000);
		config.setConnectionTimeout(10000);
		config.setEndPoint(endPoint);
		return new ObsClient(ak, sk, config);
	}

	/**
	 * 打开链接捅，一次性，不关闭
	 */
	private static void openConnectionAndDontClose() {
		if (isInit) {
			synchronized (isInit) {
				if (!isInit) {
					return;
				}
			}
		} else {
			return;
		}
		ObsConfiguration config = new ObsConfiguration();
		config.setSocketTimeout(30000);
		config.setConnectionTimeout(10000);
		config.setEndPoint(endPoint);
		obsClient = new ObsClient(ak, sk, config);
	}

	/**
	 * 关闭链接捅
	 */
	private static void closeConnection(ObsClient obsClient) {
		if (obsClient != null) {
			try {
				obsClient.close();
			} catch (IOException e) {
				log.error("", e);
			}
		}
	}

	/**
	 * 将is流上传到华为云
	 * 
	 * @param bucketName
	 * @param objectKey
	 * @param input
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	public static void uploadFile(String bucketName, String objectKey, InputStream input)
			throws FileNotFoundException, IOException {
		ObsClient openConnection = openConnection();
		try {
			InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest();
			request.setBucketName(bucketName);
			request.setObjectKey(objectKey);
			InitiateMultipartUploadResult result = openConnection.initiateMultipartUpload(request);

			UploadPartResult uploadPartResult = openConnection.uploadPart(bucketName, objectKey, result.getUploadId(),
					1, input);

			CompleteMultipartUploadRequest completeMultipartUploadRequest = new CompleteMultipartUploadRequest();
			completeMultipartUploadRequest.setBucketName(bucketName);
			completeMultipartUploadRequest.setObjectKey(objectKey);
			completeMultipartUploadRequest.setUploadId(result.getUploadId());

			PartEtag partEtag = new PartEtag();
			partEtag.setPartNumber(uploadPartResult.getPartNumber());
			partEtag.seteTag(uploadPartResult.getEtag());
			completeMultipartUploadRequest.getPartEtag().add(partEtag);

			openConnection.completeMultipartUpload(completeMultipartUploadRequest);
		} catch (ObsException e) {
			System.out.println("Response Code: " + e.getResponseCode());
			System.out.println("Error Message: " + e.getErrorMessage());
			System.out.println("Error Code:       " + e.getErrorCode());
			System.out.println("Request ID:      " + e.getErrorRequestId());
			System.out.println("Host ID:           " + e.getErrorHostId());
		} finally {
			closeConnection(openConnection);
		}
	}

	/**
	 * 获取文件的InputStream流
	 * 
	 * @param bucketName
	 * @param fileKey
	 * @return
	 */
	public static InputStream getFileInputStream(String bucketName, String fileKey) {
		ObsClient openConnection = openConnection();
		try {
			ObsObject obsObject = openConnection.getObject(bucketName, fileKey, null);

			return obsObject.getObjectContent();
		} finally {
			closeConnection(openConnection);
		}
	}

	/**
	 * 获取文件的byte流数组
	 * 
	 * @param bucketName
	 * @param fileKey
	 * @return
	 */
	public static byte[] getFileBytes(String bucketName, String fileKey) {
		ObsClient openConnection = openConnection();
		try {
			ObsObject obsObject = openConnection.getObject(bucketName, fileKey, null);

			return toByteArray(obsObject.getObjectContent());
		} catch (IOException e) {
			log.error("", e);
		} finally {
			closeConnection(openConnection);
		}
		return null;
	}

	/**
	 * 下载文件到配置的服务器路径
	 * 
	 * @param bucketName
	 * @param fileKey
	 */
	public static void downloadFile(String bucketName, String fileKey) {
		ObsClient openConnection = openConnection();
		try {
			File localFile = new File(dowloadFilePath + fileKey);
			if (!localFile.getParentFile().exists()) {
				localFile.getParentFile().mkdirs();
			}
			downloadToLocalFile(openConnection, bucketName, fileKey);
		} catch (ObsException e) {
			log.error("Response Code: " + e.getResponseCode());
			log.error("Error Message: " + e.getErrorMessage());
			log.error("Error Code:       " + e.getErrorCode());
			log.error("Request ID:      " + e.getErrorRequestId());
			log.error("Host ID:           " + e.getErrorHostId());
		} catch (IOException e) {
			log.error("", e);
		} finally {
			closeConnection(openConnection);
		}
	}

	/**
	 * 下载文件到指定文件夹
	 * 
	 * @param bucketName
	 * @param objectKey
	 * @throws ObsException
	 * @throws IOException
	 */
	private static void downloadToLocalFile(ObsClient obsClient, String bucketName, String objectKey)
			throws ObsException, IOException {
		ObsObject obsObject = obsClient.getObject(bucketName, objectKey, null);
		ReadableByteChannel rchannel = Channels.newChannel(obsObject.getObjectContent());

		ByteBuffer buffer = ByteBuffer.allocate(4096);
		WritableByteChannel wchannel = Channels.newChannel(new FileOutputStream(new File(dowloadFilePath + objectKey)));

		while (rchannel.read(buffer) != -1) {
			buffer.flip();
			wchannel.write(buffer);
			buffer.clear();
		}
		rchannel.close();
		wchannel.close();
	}

	/**
	 * is流转换为byte数组
	 * 
	 * @param input
	 * @return
	 * @throws IOException
	 */
	public static byte[] toByteArray(InputStream input) throws IOException {
		ByteArrayOutputStream output = new ByteArrayOutputStream();
		byte[] buffer = new byte[4096];
		int n = 0;
		while (-1 != (n = input.read(buffer))) {
			output.write(buffer, 0, n);
		}
		return output.toByteArray();
	}

	@Value("${accessKey}")
	public void setAk(String ak) {
		HuaWeiCloudFileUtil.ak = ak;
	}

	@Value("${securityKey}")
	public void setSk(String sk) {
		HuaWeiCloudFileUtil.sk = sk;
	}

	@Value("${bucketName_hot}")
	public void setHotBucketName(String hotBucketName) {
		HuaWeiCloudFileUtil.hotBucketName = hotBucketName;
	}

	@Value("${bucketName_low}")
	public void setLowBucketName(String lowBucketName) {
		HuaWeiCloudFileUtil.lowBucketName = lowBucketName;
	}

	@Value("${bucketName_bak}")
	public void setBakBucketName(String bakBucketName) {
		HuaWeiCloudFileUtil.bakBucketName = bakBucketName;
	}

	@Value("${endPoint}")
	public void setEndPoint(String endPoint) {
		HuaWeiCloudFileUtil.endPoint = endPoint;
	}

	@Value("${dowload_file_path}")
	public void setDowloadFilePath(String dowloadFilePath) {
		HuaWeiCloudFileUtil.dowloadFilePath = dowloadFilePath;
	}

	public static String getHotBucketName() {
		return hotBucketName;
	}

	public static String getLowBucketName() {
		return lowBucketName;
	}

	public static String getBakBucketName() {
		return bakBucketName;
	}
}
